<?php
namespace app\common;

use yii\base\Component;
use common\widgets\Tools;

/**
 * Class TrySafe
 * @package common
 *
 * 重试安全限制类
 */
class TrySafe extends Component {
	/**
	 * 存储的key
	 * @var
	 */
	public $key;
	/**
	 * 前缀名称
	 * @var string
	 */
	public $prefix = '';
	/**
	 * 重试次数
	 * @var int
	 */
	public $maxTries = 5;
	/**
	 * 间隔时间（秒）
	 * @var int
	 */
	public $interval = 1800;
	/**
	 * 锁定提示模板
	 * @var string
	 */
	public $blockMessage = '%s已连续错误%s次，暂时冻结，请%s后再试！';
	/**
	 * 重试提示模板
	 * @var string
	 */
	public $tryMessage = '输入的%s有误，请重新输入，还有%s次机会';

	/**
	 * 重试安全key
	 */
	const CACHE_KEY = 'tries/safe/%s';

	private $_try;

	public function __construct(array $config) {
		$this->maxTries = \Yii::$app->params['sms']['error_max_time'];
	}

	/**
	 * 获取重试数组
	 */
	public function getTry()
	{
		if(isset($this->_try) == false) {
			$cache_key = sprintf(self::CACHE_KEY, $this->key);
			$try = Tools::getOCS($cache_key);
			$this->_try = &$try;
		}else{
			$try = &$this->_try;
		}

		// 空或超时
		$time = time();
		if(empty($try) || $try[1] < $time)
		{
			$try = [0, $time+$this->interval];
		}

		return $try;
	}

	/**
	 * 修改重试信息
	 * @param $try
	 */
	public function setTry($try)
	{
		$this->_try = $try;
		$cache_key = sprintf(self::CACHE_KEY, $this->key);
		Tools::setOCS($cache_key, $try);
	}

	/**
	 * 检查重试安全
	 * @return int 剩余重试机会
	 */
	public function check() {
		return $this->maxTries - $this->getTry()[0];
	}

	/**
	 * 递增重试安全
	 * @param int $num
	 * @return int 剩余重试机会
	 */
	public function incr($num = 1) {
		$try = $this->getTry();
		// 避免>$maxTries
		$try[0] = min($try[0]+$num, $this->maxTries);
		// 保存递增
		$this->setTry($try);
		return $this->maxTries - $try[0];
	}

	/**
	 * 清理重试安全
	 */
	public function reset() {
		$cache_key = sprintf(self::CACHE_KEY, $this->key);
		Tools::deleteOCS($cache_key);
	}

	/**
	 * 获取错误信息
	 * @return string
	 */
	public function getErrorMessage()
	{
		$message = '';
		$try = $this->getTry();
		$num = $this->maxTries - $try[0];
		if($num == 0) {
			// 锁定
			$message = sprintf($this->blockMessage, $this->prefix, $this->maxTries, $this->getIntervalMessage());
		}else if($num != $this->maxTries) {
			// 剩余次数
			$message = sprintf($this->tryMessage, $this->prefix, $num);
		}
		return $message;
	}

	/**
	 * 获取间隔信息
	 * @return string
	 */
	private function getIntervalMessage()
	{
		$message = '';
		foreach([
					86400 => '%s天',
					3600 => '%s小时',
					60 => '%s分钟',
					0 => '秒',
				] as $step => $template) {
			if($this->interval >= $step) {
				// 天
				$message = sprintf($template, ceil($this->interval/$step));
				break;
			}
		}
		return $message;
	}
}